package util;

import java.awt.Rectangle;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.LinkedList;
import java.util.Properties;

import javax.swing.JOptionPane;


/**
 * This class is responsible for saving/loading settings that persist
 * between sessions.
 * @author TKington
 *
 */
public class GS {
	/** Creates the single instance. */
	private GS() { /* This is a singleton */ }
	
	/** Main frame bounds. */
	private static Rectangle frameBounds = new Rectangle(0, 0, 580, 603);
	/** Show ghost stone? */
	private static boolean showGhost = true;
	/** Click sound when stone played? */
	private static boolean clickSoundEnabled = true;
	/** Right/wrong sounds? */
	private static boolean rightSoundEnabled = true;
	/** Check for updates? */
	private static boolean checkForUpdates = true;
	/** Use proxy? */
	private static boolean useProxy = false;
	/** Proxy host. */
	private static String proxyHost = ""; //$NON-NLS-1$
	/** Proxy port. */
	private static int proxyPort = 0;
	/** Main window splitter position. */
	private static int splitterPos = 381;
	/** Last open file. */
	private static File lastFile = null;
	/** SGF editor. */
	private static File sgfEditor = null;
	/** Previous pages in history. */
	private static LinkedList<Integer> historyStack = new LinkedList<Integer>();
	/** Future pages in history. */
	private static LinkedList<Integer> futureStack = new LinkedList<Integer>();
	
	/** File format version. */
	private static final int REVISION = 1;
	
	/**
	 * Loads the persisted settings.
	 * @throws Exception if there is a problem reading the file.
	 */
	@SuppressWarnings("unchecked")
	public static void loadSettings() throws Exception {
	    ObjectInputStream in = new ObjectInputStream(new FileInputStream("viewer.dat")); //$NON-NLS-1$
	    
	    int rev = in.readInt();
	    if(rev > REVISION) {
	        String msg = "Error: viewer.dat is newer than the program!";
	        JOptionPane.showMessageDialog(null, msg);
	        Util.logSilent(new Exception(msg));
	        System.exit(-1);
	    }
	    
	    frameBounds = (Rectangle)in.readObject();
	    splitterPos = in.readInt();
	    showGhost = in.readBoolean();
	    clickSoundEnabled = in.readBoolean();
        checkForUpdates = in.readBoolean();
        useProxy = in.readBoolean();
        proxyHost = (String)in.readObject();
        proxyPort = in.readInt();
        lastFile = (File)in.readObject();
        historyStack = (LinkedList)in.readObject();
        futureStack = (LinkedList)in.readObject();
        rightSoundEnabled = in.readBoolean();
        sgfEditor = (File)in.readObject();
    
        if(useProxy) {
            Properties sysProps = System.getProperties(); 
            sysProps.put( "proxySet", "true" ); //$NON-NLS-1$ //$NON-NLS-2$
            sysProps.put( "proxyHost", proxyHost); //$NON-NLS-1$
            sysProps.put( "proxyPort", String.valueOf(proxyPort)); //$NON-NLS-1$
        }
	    
	    in.close();
	}
	
	/**
	 * Saves the current settings.
	 * @throws IOException if there is a problem writing the file
	 */
	public static void saveSettings() throws IOException {
	    ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("viewer.dat")); //$NON-NLS-1$
	    
	    out.writeInt(REVISION);
	    out.writeObject(frameBounds);
	    out.writeInt(splitterPos);
	    out.writeBoolean(showGhost);
	    out.writeBoolean(clickSoundEnabled);
	    out.writeBoolean(checkForUpdates);
	    out.writeBoolean(useProxy);
	    out.writeObject(proxyHost);
	    out.writeInt(proxyPort);
	    out.writeObject(lastFile);
	    out.writeObject(historyStack);
	    out.writeObject(futureStack);
	    out.writeBoolean(rightSoundEnabled);
	    out.writeObject(sgfEditor);
	    
	    out.close();
	}

	/**
	 * Returns the bounding rectangle of the main frame.
	 * @return the bounding rectangle
	 */
	public static Rectangle getFrameBounds() { return frameBounds; }
	
	/**
	 * Sets the bounding rectangle for the main frame.
	 * @param r the bounding rectangle
	 */
	public static void setFrameBounds(Rectangle r) { frameBounds = r; }
	
	/**
	 * Returns whether or not the user wants to see a ghost stone.
	 * @return true if the ghost should be shown
	 */
	public static boolean getShowGhost() { return showGhost; }
	
	/**
	 * Sets whether the user wants to see a ghost stone.
	 * @param s true if the ghost should be shown
	 */
	public static void setShowGhost(boolean s) { showGhost = s; }
	
	/**
	 * Returns whether the sound of the stones hitting the board is enabled.
	 * @return true if the sound is enabled
	 */
	public static boolean getClickSoundEnabled() { return clickSoundEnabled; }
	
	/**
	 * Sets whether the sound of the stones hitting the board is enabled.
	 * @param e true to enable the sound
	 */
	public static void setClickSoundEnabled(boolean e) { clickSoundEnabled = e; }
	
	/**
	 * Returns whether the program should check for updates at startup.
	 * @return true if the program should check for updates
	 */
	public static boolean getCheckForUpdates() { return checkForUpdates; }
	
	/**
	 * Sets whether the program should check for updates at startup.
	 * @param c true to check for updates
	 */
	public static void setCheckForUpdates(boolean c) { checkForUpdates = c; }
	
	/**
	 * Returns whether the program should use a proxy to access the internet.
	 * @return true if a proxy is needed
	 */
	public static boolean getUseProxy() { return useProxy; }
	
	/**
	 * Sets whether the program should use a proxy to access the internet.
	 * @param u true to use a proxy
	 */
	public static void setUseProxy(boolean u) { useProxy = u; }
	
	/**
	 * Returns the proxy host.
	 * @return the proxy host
	 */
	public static String getProxyHost() { return proxyHost; }
	
	/**
	 * Sets the proxy host.
	 * @param h the proxy host
	 */
	public static void setProxyHost(String h) { proxyHost = h; }
	
	/**
	 * Returns the proxy port.
	 * @return the proxy port
	 */
	public static int getProxyPort() { return proxyPort; }
	
	/**
	 * Sets the proxy port.
	 * @param p the proxy port
	 */
	public static void setProxyPort(int p) { proxyPort = p; }
	
	/**
	 * Sets the position of the splitter between the board and the text pane. 
	 * @param p the new splitter position
	 */
	public static void setSplitterPos(int p) { splitterPos = p; }
	
	/**
	 * Returns the position of the splitter between the board and the text pane.
	 * @return the splitter position
	 */
	public static int getSplitterPos() { return splitterPos; }
	
	/**
	 * Sets the last file the user opened.
	 * @param f the last file that was opened
	 */
	public static void setLastFile(File f) { lastFile = f; }
	
	/**
	 * Returns the last file the user opened.
	 * @return the last file that was opened
	 */
	public static File getLastFile() { return lastFile; }
	
	/**
	 * Returns the history stack.
	 * @return the history stack
	 */
	public static LinkedList<Integer> getHistoryStack() { return historyStack; }
	
	/**
	 * Sets the history stack.
	 * @param h the history stack
	 */
	public static void setHistoryStack(LinkedList<Integer> h) { historyStack = h; }
	
	/**
	 * Returns the future stack.
	 * @return the future stack
	 */
	public static LinkedList<Integer> getFutureStack() { return futureStack; }
	
	/**
	 * Sets the future stack.
	 * @param f the future stack
	 */
	public static void setFutureStack(LinkedList<Integer> f) { futureStack = f; }
	
	/**
	 * Sets right/wrong sound enabled
	 * @param e true to enable
	 */
	public static void setSoundEnabled(boolean e) { rightSoundEnabled = e; }
	
	/**
	 * Returns whether right/wrong sound enabled.
	 * @return true if enabled
	 */
	public static boolean getSoundEnabled() { return rightSoundEnabled; }
	
	/**
	 * Sets the SGF editor.
	 * @param f the SGF Editor
	 */
	public static void setSGFEditor(File f) { sgfEditor = f; }
	
	/**
	 * Returns the current SGF editor.
	 * @return the SGF editor
	 */
	public static File getSGFEditor() { return sgfEditor; }
}
